﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Core.h".
//-------------------------------------------------------------------

#ifndef _UXS_UNSIGNED_FLOAT_TYPE_H
#define _UXS_UNSIGNED_FLOAT_TYPE_H

#pragma once

#include "TFloat.h"

namespace UX_STL
{
namespace UXTypes
{

#	define _UFLOAT_OVERFLOW( _large, _real )	ASSERT( _large != _real and "overflow" )

#	define _UFLOAT_OPERATOR( _op ) \
		template <typename T>		 Self&	operator _op##= (const T& right)					{ Set( Get() _op FT(right) );  return *this; } \
									 Self	operator _op  (const Self& right) const				{ return Get() _op right.Get(); } \
		template <typename T>		 Self	operator _op  (const T& right) const				{ return Get() _op right; } \
		template <typename T> friend T		operator _op  (const T& left, const Self& right)	{ return left _op right.Get(); } \

#	define _UFLOAT_CMP_OPERATOR( _op ) \
									 bool operator _op (const Self& right) const			{ return Get() _op right.Get(); } \
		template <typename T>		 bool operator _op (const T& right)		const			{ return Get() _op right; } \
		template <typename T> friend bool operator _op (const T& left, const Self& right)	{ return left _op right.Get(); } \



	//
	// Unsigned Float
	//

	template <typename FT, typename IT, usize Mbits, usize Ebits>
	struct TUFloat
	{
		// types
		typedef TUFloat< FT, IT, Mbits, Ebits >		Self;
		typedef FT									float_t;

		struct TBits
		{
			IT	m	: Mbits;
			IT	e	: Ebits;
		};


		// variables
		union {
			TBits	_bits;
			IT		_value;
		};


		// constructor
		TUFloat(): _value(0) {}

		template <typename T>
		explicit
		TUFloat(const T& t)						{ Set( FT( t ) ); }


		// type cast
		operator float_t () const				{ return Get(); }


		// unary operators
		Self &	operator ++ ()					{ Set( Get()+1 );  return *this; }
		Self &	operator -- ()					{ Set( Get()-1 );  return *this; }
		float_t	operator ++ (int) 				{ float_t  temp( Get() );  ++(*this);  return temp; }
		float_t	operator -- (int) 				{ float_t  temp( Get() );  --(*this);  return temp; }
		bool	operator ! ()	const			{ return not _value; }


		// binary operators
		_UFLOAT_OPERATOR( +  );
		_UFLOAT_OPERATOR( -  );
		_UFLOAT_OPERATOR( *  );
		_UFLOAT_OPERATOR( /  );
		_UFLOAT_OPERATOR( %  );
		_UFLOAT_OPERATOR( |  );
		_UFLOAT_OPERATOR( &  );
		_UFLOAT_OPERATOR( ^  );
		_UFLOAT_OPERATOR( >> );
		_UFLOAT_OPERATOR( << );

		_UFLOAT_CMP_OPERATOR( == );
		_UFLOAT_CMP_OPERATOR( != );
		_UFLOAT_CMP_OPERATOR( >  );
		_UFLOAT_CMP_OPERATOR( >= );
		_UFLOAT_CMP_OPERATOR( <  );
		_UFLOAT_CMP_OPERATOR( <= );


		// methods
		static usize	Mantissa()				{ return Mbits; }
		static usize	Exponent()				{ return Ebits; }

		//static FT		Epsilon()				{  }
		
		IT		GetMantissaBit()	const		{ return _bits.m; }
		IT		GetExponentBit()	const		{ return IT(_bits.e) - (1<<(Ebits-1)) + 1; }
		FT		GetMantissa()		const		{ return FT(1) + FT(_bits.m) / FT( (1<<Mbits)-1 ); }
		FT		GetExponent()		const		{ return UXMath::Pow2<FT,IT>( GetExponentBit() ); }
		FT		Get()				const		{ return GetMantissa() * GetExponent(); }

		void	Set(const float_t &f);
	};


	typedef TUFloat< float, uint8,   4, 4 >		float_m4_e4_t;
	typedef TUFloat< float, uint16,  5, 5 >		float_m5_e5_t;
	typedef TUFloat< float, uint16,  6, 5 >		float_m6_e5_t;
	typedef TUFloat< float, uint16,  9, 5 >		float_m9_e5_t;
	typedef TUFloat< float, uint16, 11, 5 >		float_m11_e5_t;

	typedef float_m4_e4_t						float8u_t;
	typedef float_m5_e5_t						float10u_t;
	typedef float_m6_e5_t						float11u_t;
	typedef float_m9_e5_t						float14u_t;
	typedef float_m11_e5_t						float16u_t;


	
	template <typename FT, typename IT, usize Mbits, usize Ebits>
	inline void TUFloat<FT,IT,Mbits,Ebits>::Set(const float_t &val)
	{
		enum {
			EXP	= (1 << (Ebits-1)) - 1,
		};

		const typename TFloatSimilar<float_t>::type	f( val );

		ASSERT( f._bits.s == 0 and "only unsigned values suppoted" );

		IT	tmp;

		_bits.e = tmp = f.GetExponentBit() + EXP;
		_UFLOAT_OVERFLOW( tmp, _bits.e );

		_bits.m = tmp = f.GetMantissaBit() >> ( f.Mantissa() - Mantissa() );
		_UFLOAT_OVERFLOW( tmp, _bits.m );
	}


#	undef _UFLOAT_OVERFLOW
#	undef _UFLOAT_OPERATOR
#	undef _UFLOAT_CMP_OPERATOR

//-------------------------------------------------------------------

}	// UXTypes
}	// UX_STL

#endif	// _UXS_UNSIGNED_FLOAT_TYPE_H